<?php
/********************************************************************************\
**                                                                              **
**  Copyright (C) 2010 Gary Warman                                              **
**                                                                              **
**  This file is a part of the WebFormGenerator library.                        **
**                                                                              **
**                                                                              **
**  webformgenerator is free software: you can redistribute it and/or modify it **
**  under the terms of the GNU General Public License as published by  		    **
**  the Free Software Foundation, version 3 of the license or any later version.**
**                                                                              **
**  This application and its source code is distributed AS-IS, WITHOUT ANY      **
**  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS   **
**  FOR A PARTICULAR PURPOSE. See the GNU General Public License for more       **
**  details.                                                                    **
**                                                                              **
**  You should have recieved a copy of the GNU General Public License along     **
**  with this code. If not, see <http://www.gnu.org/licenses/>                  **
**                                                                              **
**  webformgenerator is a library designed to automatically populate forms with **
**  fields from a mysql table provided.  Developers of webformgenerator or those**
**  associated with webformgenerator are in no way responsible for its users or **
**  usages manifested by its users, or damages caused by the environment        **
**  or programs made in the environment.                                        **
**                                                                              **
\********************************************************************************/

class FormGenerator {
        private $db = "";
        private $tb = "";       
        private $postText = "";
        private $method = "";
        private $exec = false;
        function __construct($user,$password,$host,$db,$tb, $pt = "Post", $m = "post") {
                $m = strtolower($m);
                if($m != "post" || $m != "get") { $m = "get"; }
                $this->db = $db;
                $this->tb = $tb;
                mysql_connect($host,$user,$password) or die("erorororor: " .mysql_error());
                mysql_select_db($db);
        $this->postText = $pt;
                $this->method = $m;
        }
        public function execute($val) {
             $this->exec = !!$val;
        }
        public function canExec() {
             return $this->exec;
        }
        public function getDatabase() {
                return $this->db;
        }
        public function getPostText() {
                return $this->postText;
        }
        public function getTable() {
                return $this->tb;
        }
        public function getMethod() {
                return $this->method;
        }
        public function setDatabase($db) {
                $this->db = $db;
                mysql_select_db($this->getDatabase());
        }
        public function setTable($tb) {
                $this->tb = $tb;                
        }
    public function setPostText($pt) {
                $this->postText = $pt;
        }
        public function setMethod($m) {
                $m = strtolower($m);
                if($m != "post" || $m != "get") {
                        $m = 'get';
                }
                $this->method = $m;
        }
        public function getRow() {
                $q = mysql_query("SELECT * FROM ".$this->getTable()." LIMIT 1");
                if(!$q) {
                 die("Error: " .mysql_error());
                 }
                 return $q;
        }
        public function getRowLength($query) {          
                return mysql_num_fields($query);
        }
        public function getRowNames($query) {
                $out = array();
                for($i=0;$i<$this->getRowLength($query);$i++) {
                        array_push($out,mysql_field_name($query,$i));
                }
                return $out;
        }
public function getType($field) {
        $q = mysql_query("DESCRIBE ".$this->getTable());        
        $type = -1;
        while(($row = mysql_fetch_assoc($q)) !== false) {       
                if($row["Field"] == $field) {
                        $type = $row["Type"];                                   
                }
        }
        return $type;
}

public function isPrimary($field) {
        $q = mysql_query("DESCRIBE ".$this->getTable()) or die("ERROROROROROR:  ".mysql_error());       
        $ret = false;
        while(($row = mysql_fetch_assoc($q)) !== false) {               
                if($row["Field"] == $field) {
                        if($row["Key"] == "PRI") {                              
                                $ret = true;
                        }
                }
        }
        return $ret;
}

public function generateForm($action = "::self", $ajax = true, $code = "") {
$tb = $this->getTable();
$db = $this->getDatabase();
if($action == "::self") { $action = $_SERVER["PHP_SELF"]; }
$method = "post";
?>
<script src="jq.js" type="text/javascript"></script>
<script src="ajaxupload.js"></script>
<script type="text/javascript">
function getVars() { //Get values from the input fields.
        ret = {}
        $("input").add(".input-box").each(function() { //Loop through each input field.
                name = $(this).attr("name");
                ret[name] = $(this).val(); //Generate associative array: ret[name_of_field] = value_of_field;
        });
        return ret;
}

function autopush(elem,format) { //For fields that have a predefined format, autopush certain characters in
				len = $(elem).val().length;				
				char = format.charAt(len)								
				if(char == ":" || char == "-" || char == " ") { //In this case, one of ":- "
					$(elem).val($(elem).val()+char);
				}
}
function validate() { // Validate input
	//ToDo: properly validate date fields.
	ret = true
	$("input").each(function() { // Loop through the input fields.
		if($(this).val() == "") {
			alert("field empty: "+$(this).attr("id").replace(/in_/,""));
			ret = false;
			return false;
		}
		return true;
	})
	return ret;
}
function readyfunc() { // Function to be called on document.ready
aups = new Array();
		$(".input-box").each(function() { $(this).css("min-width","200px").css("max-width","350px"); });
<?php
                if($ajax) { //If an AJAX form is requested. Disregard this for now.
                        if($code == "") {
                                $code = '$("#output").html(data);';
                        }
?>
        $("form#<?php echo $tb; ?>").bind("submit",function() { if(!validate()) { return false; } $.post("<?php echo $action; ?>", getVars(), function(data) { <?php echo $code; ?> });
		
         return false; })
<?php
				} else {
?>
		$("form#<?php echo $tb; ?>").bind("submit",function() { return validate(); });
<?php
		}
?>
		 $("input.is-num").each(function() { $(this).bind("keypress",function (e) { //Bind input constrictor to number fields.
			code = e.which
			keycode=false;
			if(code == 0) { code = e.keyCode; keycode=true; }
			if(code >= 48 && code <= 57 || code == 8 || code == 9 || (keycode && (code == 16 || code == 37 || code == 39))) { // If you press a number, arrow keys, backspace, or tab....
				return true;
			} else {
				return false;
			}
		})});
		 $("input.is-dec").each(function() { $(this).bind("keypress",function (e) { //Bind input constrictor to decimal fields.
			code = e.which			
			keycode=false;
			if(code == 0) { code = e.keyCode; keycode=true; }			
			if((code >= 48 && code <= 57) || code == 46 || code == 8 || code == 9 || (keycode && (code == 16 || code == 37 || code == 39))) { // If you press a number, arrow keys, backspace, tab, or period...	
				if($(this).val().match(/\./) && code == 46) {
					return false
				}
				return true;
			} else {
				return false;
			}
		})});
		$("input.is-date").each(function() { //Bind input constrictor to date fields. 
			self = $(this);
			format = "YYYY-MM-DD"		//Format declaration.						
			helper = $("div#"+$(this).attr("name")+"_helper"); //Helper div to highlight characters currently entered.
			helper.html(format);
			self.val(format);			
			self.bind("focus",function() {
				focus(this);
			})
			self.bind("keypress",function(e) {
						var format = "YYYY-MM-DD"		
			autopush(this,format);
							len = $(this).val().length;
			helper = $("div#"+$(this).attr("name")+"_helper");
			g = helper.text()
			v = g.substr(len);
			g = g.substr(0,len);
			helper.html("<b>"+g+"</b>"+v);
			code = e.which						
			keycode=false;			
			if(code == 0) { code = e.keyCode; keycode=true; }		
			char = $(this).val().charAt($(this).val().length-1) 
			if(code == 8 && (char == ":" || char == "-" || char == " ")) { $(this).val($(this).val().substr(0,$(this).val().length-2)); return false; }
			if(code == 8 || code == 9 || (keycode && (code == 16))) { return true; }	
			var forex = new RegExp("^"+format.substr(0,len+1).replace(/[A-Z]/g,"\\d")+"$");						
			if(!($(this).val()+String.fromCharCode(e.which)).match(forex)) { return false; }
			if((code >= 48 && code <= 57) || code == 45) {				
				if($(this).val().count("-") >= 3 && code == 45) {
					return false
				}
				return true;
			} else {
				return false;
			}
			});
			self.bind("blur",function() {
				format = "YYYY-MM-DD"			
				blur(this,format);					
			});
		})
				$("input.is-datetime").add("input.is-timestamp").each(function() {
			self = $(this);
			format = "YYYY-MM-DD HH:MM:SS"				
			$("div#"+$(this).attr("name")+"_helper").html(format);
			self.val(format);			
			self.bind("focus",function() {
				focus(this);
			})
			self.bind("keypress",function(e) {			
			char = ""
			format = "YYYY-MM-DD HH:MM:SS"
			autopush(this,format)	
			char = $(this).val().charAt($(this).val().length-1)			
						len = $(this).val().length;
			helper = $("div#"+$(this).attr("name")+"_helper");
			g = helper.text()
			v = g.substr(len);
			g = g.substr(0,len);
			helper.html("<b>"+g+"</b>"+v);		
			code = e.which						
			keycode=false;			
			if(code == 0) { code = e.keyCode; keycode=true; }					
			if(code == 8 && (char == ":" || char == "-" || char == " ")) { $(this).val($(this).val().substr(0,$(this).val().length-2)); return false; }			
			if(code == 8 || code == 9 || (keycode && (code == 16))) { return true; }
			var forex = new RegExp("^"+format.substr(0,len+1).replace(/[A-Z]/g,"\\d")+"$");						
			if(!($(this).val()+String.fromCharCode(e.which)).match(forex)) { return false; }		
			if((code >= 48 && code <= 57) || code == 45  || code == 32 || code == 58) {				
				if($(this).val().count("-") >= 3 && code == 45) {
					return false
				}
				return true;
			} else {
				return false;
			}
			});
			self.bind("blur",function() {
				format = "YYYY-MM-DD HH:MM:SS"			
			    blur(this,format);
			});
		})
		$("input.file-upload").each(function() {			
			id = $(this).attr("id");
			origid = id.replace(/_sub/,"");
			var div = $("#"+id);
			alert("making ajaxupload for "+origid+ " (button id: "+origid+")")
			AJAX = {}
			AJAX.name = origid;			
			AJAX.autosubmit = true;			
			AJAX.action = "<?php echo $action; ?>";
			AJAX.onComplete = function(f,r) {
				alert(r);
			}
			aj = new AjaxUpload(div, AJAX);			
		});	
}
String.prototype.count=function(s1) {  //Count occurrences of a certain character/substring in a string.
	return (this.length - this.replace(new RegExp(s1,"g"), '').length) / s1.length;
}
function debug(data) { //Output data to a debug div.
	$("#debug").html(data);
}
function focus(elem) { //Standard focus function.
	$(elem).select()
	$(elem).val("");
}
function blur(elem,format) { //Standard blur function for date fields
				formex = new RegExp("^"+format.replace(/[A-Z]/gi,"\\d")+"$");	
				if(!$(elem).val().match(formex)) {
					alert("Invalid syntax used for: "+$(elem).attr("name").replace(/in_/,""));
					$(elem).select();
					$(elem).focus();
				} else {
					$(elem).attr("disabled","disabled")
					$(elem).unbind("focus")
					$(elem).unbind("blur")
					reedit = $("<input />");
					reedit.attr("type","button");
					reedit.attr("href","#");
					reedit.attr("id",$(elem).attr("id")+"_reedit");
					reedit.attr("value","Click to reenable");
					reedit.bind("mousedown",function() {
						id = $(elem).attr('id').replace(/_reedit/,"");
						inp = $("input#"+id);
						inp.removeAttr("disabled");
						inp.bind("focus",function() { focus(this); })
						inp.bind("blur", function() { blur(this,format); })
						$(this).remove();
					})
					$(elem).parent().append(reedit)
				}
}

$(document).ready(readyfunc)
</script>
<?php       
           $query = $this->getRow();
           if(!$query) 
                        die("I want an error to appear here: ".mysql_error());
                $rows = $this->getRowNames($query);
                echo "<form id='$tb' method='post' action='$action' enctype='multipart/form-data'>\n";
                echo "<table>";
                foreach ($rows as $index => $name) {
                        if($this->isPrimary($name)) { continue; }
                        $type = $this->getType($name);
                        $len = "";
                        $opt = "";
                        if(preg_match("/^(.+)\((.+)\)$/i",$type,$match)) {                              
                                $type = $match[1];
                                $len = $match[2];                               
                                echo "<!-- type(val) = $type($len) -->\n";
                                if($this->getGenericType($type) == "ENUM")
                                        $opt = explode(",",$len);                                       
                        }
                        $type = $this->getGenericType($type);                   
                        $len = ($len != "") ? ("maxlength='$len'") : ("");
                        echo "<tr><td><label for='in_$name'>$name: </label></td><td>";
                        if($type == "FILE") {
							$this->setMethod("post");
?>
<script type="text/javascript">
$("form:first").attr("method","post");
</script>
<?php						
							if($ajax) {
                                echo "<input type='text' name='in_$name' id='in_$name' class='input-box skipme' disabled='disabled'/><input type='button' id='in_".$name."_sub' class='file-upload'  value='Browse...'/>";
							} else {
								echo "<input type='file' name='in_$name' id='in_$name' class='input-box' />";
							}						
                        } else if($type == "INTEGER") {
                                echo "<input type='text' name='in_$name' id='in_$name' class='input-box is-num' $len />";
                        } else if($type == "DEC") {
								echo "<input type='text' name='in_$name' id='in_$name' class='input-box is-dec' $len />";
						} else if($type == "CHAR") {
                                echo "<input type='text' name='in_$name' class='input-box' $len />";
						} else if($type == "DATE") {
								echo "<div><input type='text' name='in_$name' id='in_$name' class='input-box is-date' /> <div id='in_".$name."_helper' name='in_".$name."_helper' style='display: inline'></div></div>";
						} else if($type == "DATETIME") {
								echo "<div><input type='text' name='in_$name' id='in_$name' class='input-box is-datetime' /> <div id='in_".$name."_helper' name='in_".$name."_helper' style='display: inline'></div></div>";
						} else if($type == "TIMESTAMP") {
								echo "<div><input type='text' name='in_$name' id='in_$name' class='input-box is-timestamp' /> <div id='in_".$name."_helper' name='in_".$name."_helper' style='display: inline'></div></div>";
                        } else if($type == "ENUM") {
                                echo "<select name='in_$name' class='input-box'>\n";                            
                                foreach($opt as $ind => $value) {
                                        echo "<option value=\"$value\">$value</option>\n";
                                }
                                echo "</select>";
                                
                        } else {
                                echo "<textarea rows='5' cols='50' name='in_$name' class='input-box' $len></textarea>";
                        }
                        echo "</td></tr>\n";
                }
                echo "<tr><td><input type='checkbox' name='post' id='post' value='true' /></td><td><label for='post'> Push to DB?</label></td></tr>\n";
                echo "<tr><td><input type='submit' value='".$this->postText."' name='submit' id='submit'/></td></tr>\n";
                if($ajax) {
                        echo "<tr><td><div id='output' name='output'></div></td></tr>\n";						
                }
				echo "<tr><td><div id='debug' name='debug'></div></td></tr>\n";
                echo "</table>";
                $this->makeHiddenInput("db",$db);
                $this->makeHiddenInput("tb",$tb);
                echo "</form>";
}
public function getGenericType($type) {    
        $gen = "TEXT";
        if(stristr($type,"int")) {
                $gen = "INTEGER";
        } else if(preg_match("/decimal|float|double|real/i",$type)) {
                $gen = "DEC";
        } else if(stristr($type,"blob")) {
                $gen = "FILE";
        } else if(preg_match("/varchar|char/i",$type)) {
                $gen = "CHAR";  
        } else if(preg_match("/set|enum/i",$type)) {
                $gen = "ENUM";
        } else if($type == "date") {
				$gen = "DATE";
		} else if($type == "datetime") {
				$gen = "DATETIME";
		} else if ($type == "timestamp") {
				$gen = "TIMESTAMP";
		}
                return $gen;
}
public function getValues($arr) {
        $ret = array();
        foreach($arr as $key => $value) {
                if(stristr($key,"in_")) {
						$k = str_replace("in_","",preg_replace("/'/","",stripslashes($key)));
						$v = stripslashes($value);
                        $ret[$k] = $v;
						echo "<!-- found key: $k with value: $v -->";
						
                } else {
                        $continue;
                }
        }
        return $ret;
}
private function makeHiddenInput($name,$value) {
        echo "<input type='hidden' name='$name' value='$value' />\n";
}
public function isSubmitted() {
        return (isset($_POST["submit"]) && $_POST["submit"] == $this->getPostText()) || (isset($_GET["submit"]) && $_GET["submit"] == $this->getPostText());
}
private function mres($value) {
        return mysql_real_escape_string($value);
}
public function handleUploads() {
	if(!empty($_FILES)) {
		$files = "";
		foreach($_FILES as $filename => $value) {
			if($filename == "") { return; }
			$fname = $filename;
			echo "<!-- making new file: $fname -->\n";
			$files .= "$fname<br />\n";
			$contents = file_get_contents($value["tmp_name"]);
			if(file_put_contents($fname,$contents) === false) {
				die("could not upload file: $fname");
			}
		}
	if(isset($_POST["die"])) { die("uploaded: $files"); }
	echo "uploaded: $files";
	}
}
private function genQuery() {		//Generate a mysql query based on what is given.
		$r = $this->getValues($_POST);        
		if(!empty($_FILES)) { //Any files uploaded?
			foreach($_FILES as $file => $v) { //Handle them here.
				$key = str_replace("in_","",$file); /
				$value = $v["name"];
				$r[$key] = $value;
			}
		}
        $q = "INSERT INTO ".$this->getTable()." ("; //Start of query: INSERT INTO tblname
        $fields = array(); //List of fields
        $values = array(); // List of values
        foreach($r as $field => $value) { //Loop through fields.
                array_push($fields,$field); //Push field into the field arr
                $type = $this->getType($field); //Get the type of the field
                $gentype = $this->getGenericType($type);                 //And the generic type (to handle formatting of data
                echo "<!--\n val: $value\n field: $field\n type: $type\n gentype: $gentype\n-->"; //Extraneous testing comment.
                switch($gentype) { //Switch to determine what to do with data based on received data.
                        case "INTEGER":                 
                        case "DEC":
                                break;
                        case "FILE":       
								if(!file_exists("in_".$field)) 
									file_put_contents("in_".$field,file_get_contents($_FILES["in_".$field]["tmp_name"]));
                                $value = "'".addslashes(file_get_contents("in_".$field))."'";
								unlink("in_".$field);
                                break;
                        case "TEXT":
                        case "CHAR":
                                $value = "'".$this->mres($value)."'";
                                break;
                        case "ENUM":
                                $value = stripslashes($value);
                                break;
			case 'DATE':
			case 'DATETIME':
			case 'TIMESTAMP':
				$value = "'".$value."'";
				break;
                        }
                array_push($values,$value);
        }
        $q .= implode(", ",$fields) . ") VALUES (".implode(", ",$values).")"; //Join values
        return $q; //Return generated query.
}
public function pushToDB($push = false) {
        echo "<!-- push changes: ".$this->canExec()."-->\n"; //debug output
        $q = $this->genQuery(); //Generate a query        
        if($this->canExec()) { //If the query should be performed...
                mysql_query($q) or die("Error: ".mysql_error()); //Perform it. Or die. Whichever, you know.
                echo "Successfully pushed to database: <br />\n"; //Confirmation message.
                $vals = $this->getValues($_POST); //Get values for more confirmation to user
                foreach($vals as $name => $val) {
                       echo "$name: $val<br />\n"; //field_name: field_value
               }

        } else { 
                echo $q; //Just echo the query.
        }
}
public function debug() { //Extraneous debug function.
    echo "Database: ".$this->getDatabase()."<br />\n";
    echo "Table: ".$this->getTable() . "<br />\n";
    echo "Method: ".$this->getMethod()."<br />\n";
    echo "Post text: ".$this->getPostText()."<br />\n";
}       
}

